
/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/


#include <math.h>
#include <stdlib.h>
#include <flgrCoreDispatch.h>
#include <flgrCoreVector.h>
#include <flgrCoreData.h>
#include <flgrCoreCopy.h>
#include <flgrCoreIO.h>
#include <flgrCoreShift.h>
#include <flgrCoreTranspose.h>
#include "flgrCoreShear.h"


/*!
 * \defgroup group_fulguro_core_shear Shear Based Transformation
 * \ingroup group_fulguro_core
 * @{
 */
#define FLGR_MACRO_SHEAR_X_2D(dtype)					\
  FLGR_Vector *vec;							\
  fgFLOAT64 alpha,a;							\
  int i,k,shift;							\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  vec = flgr_vector_create(datsrc->spp,datsrc->type);			\
  flgr_vector_clear(vec);						\
									\
  a = (angle * FLGR_PI)/180;						\
									\
  flgr1d_copy_##dtype##_##dtype(datdest->row[yc], datsrc->row[yc]);	\
									\
  alpha = tan(a);							\
  alpha = (alpha < 0) ? (-1*alpha) : (alpha);				\
									\
  if(angle<0) {								\
    for(i=1,k=yc-1 ; i<yc ; i++,k--) {					\
      shift = (int) (alpha * ((fgFLOAT64) i));				\
      flgr1d_shift_right_##dtype(datdest->row[k], datsrc->row[k],	\
				 shift, vec);				\
    }									\
    for(k=yc+1,i=1 ; k<datsrc->size_y ; i++,k++) {			\
      shift = (int) (alpha * ((fgFLOAT64) i));				\
      flgr1d_shift_left_##dtype(datdest->row[k], datsrc->row[k],	\
				shift, vec);				\
    }									\
  }else {								\
    for(i=1,k=yc-1 ; i<yc ; i++,k--) {					\
      shift = (int) (alpha * ((fgFLOAT64) i));				\
      flgr1d_shift_left_##dtype(datdest->row[k], datsrc->row[k],	\
				shift, vec);				\
    }									\
    for(k=yc+1,i=1 ; k<datsrc->size_y ; i++,k++) {			\
      shift = (int) (alpha * ((fgFLOAT64) i));				\
      flgr1d_shift_right_##dtype(datdest->row[k], datsrc->row[k],	\
				 shift, vec);				\
    }									\
  }									\
									\
  flgr_vector_destroy(vec)


void flgr2d_shear_x_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_X_2D(fgBIT);
}
void flgr2d_shear_x_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_X_2D(fgUINT8);
}
void flgr2d_shear_x_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_X_2D(fgUINT16);
}
void flgr2d_shear_x_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_X_2D(fgUINT32);
}
void flgr2d_shear_x_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_X_2D(fgINT8);
}
void flgr2d_shear_x_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_X_2D(fgINT16);
}
void flgr2d_shear_x_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_X_2D(fgINT32);
}
void flgr2d_shear_x_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_X_2D(fgFLOAT32);
}
void flgr2d_shear_x_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_X_2D(fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Horizontal Shear
 *  @param datdest : pointer to FLGR_Data1D
 *  @param datsrc : pointer to FLGR_Data1D
 *  @param xc : column center
 *  @param yc : row center
 *  @param angle : fgFLOAT64 (degree)
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_shear_x(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(angle>360) {
    POST_ERROR("angle > 360\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if(angle<-360) {
    POST_ERROR("angle < -360\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if((ret = flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__)) != FLGR_RET_OK) return ret;

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr2d_shear_x,datdest,datsrc,xc,yc,angle);

}






#define FLGR_MACRO_SHEAR_Y_2D(dtype)					\
  FLGR_Vector *vec;							\
  FLGR_Data2D *tdatdest;						\
  FLGR_Data2D *tdatsrc;							\
  fgFLOAT64 alpha,a;							\
  int i,k,shift;							\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  tdatsrc = flgr2d_create_pixmap(datsrc->size_x,datsrc->size_y,		\
				 datsrc->spp,datsrc->type);		\
  tdatdest = flgr2d_create_pixmap(datsrc->size_x,datsrc->size_y,	\
				  datsrc->spp,datsrc->type);		\
									\
  flgr2d_transpose_##dtype(tdatsrc,datsrc);				\
 									\
  vec = flgr_vector_create(datsrc->spp,datsrc->type);			\
  flgr_vector_clear(vec);						\
									\
  a = (angle * FLGR_PI)/180;						\
									\
  flgr1d_copy_##dtype##_##dtype(tdatdest->row[xc], tdatsrc->row[xc]);	\
									\
  alpha = sin(a);							\
  alpha = (alpha < 0) ? (-1*alpha) : (alpha);				\
									\
  if(angle<0) {								\
    for(i=1,k=xc-1 ; i<xc ; i++,k--) {					\
      shift = (int) (alpha * ((fgFLOAT64) i));				\
      flgr1d_shift_left_##dtype(tdatdest->row[k], tdatsrc->row[k],	\
				 shift, vec);				\
    }									\
    for(k=xc+1,i=0 ; k<tdatsrc->size_y ; i++,k++) {			\
      shift = (int) (alpha * ((fgFLOAT64) i));				\
      flgr1d_shift_right_##dtype(tdatdest->row[k], tdatsrc->row[k],	\
				shift, vec);				\
    }									\
  }else {								\
    for(i=1,k=xc-1 ; i<xc ; i++,k--) {					\
      shift = (int) (alpha * ((fgFLOAT64) i));				\
      flgr1d_shift_right_##dtype(tdatdest->row[k], tdatsrc->row[k],	\
				 shift, vec);				\
    }									\
    for(k=xc+1,i=1 ; k<tdatsrc->size_y ; i++,k++) {			\
      shift = (int) (alpha * ((fgFLOAT64) i));				\
      flgr1d_shift_left_##dtype(tdatdest->row[k], tdatsrc->row[k],	\
				shift, vec);				\
    }									\
  }									\
									\
  flgr2d_transpose_##dtype(datdest,tdatdest);				\
 									\
  flgr2d_destroy(tdatdest);						\
  flgr2d_destroy(tdatsrc);						\
  flgr_vector_destroy(vec)


void flgr2d_shear_y_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_Y_2D(fgBIT);
}
void flgr2d_shear_y_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_Y_2D(fgUINT8);
}
void flgr2d_shear_y_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_Y_2D(fgUINT16);
}
void flgr2d_shear_y_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_Y_2D(fgUINT32);
}
void flgr2d_shear_y_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_Y_2D(fgINT8);
}
void flgr2d_shear_y_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_Y_2D(fgINT16);
}
void flgr2d_shear_y_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_Y_2D(fgINT32);
}
void flgr2d_shear_y_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_Y_2D(fgFLOAT32);
}
void flgr2d_shear_y_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_Y_2D(fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Horizontal Shear
 *  @param datdest : pointer to FLGR_Data1D
 *  @param datsrc : pointer to FLGR_Data1D
 *  @param xc : column center
 *  @param yc : row center
 *  @param angle : fgFLOAT64 (degree)
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_shear_y(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(angle>360) {
    POST_ERROR("angle > 360\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if(angle<-360) {
    POST_ERROR("angle < -360\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if((ret = flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__)) != FLGR_RET_OK) return ret;

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr2d_shear_y,datdest,datsrc,xc,yc,angle);

}




#define FLGR_MACRO_SHEAR_CIRCULAR_X_2D(dtype)				\
  fgFLOAT64 alpha,a;							\
  int i,k,shift_circular;						\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  a = (angle * FLGR_PI)/180;						\
									\
  flgr1d_copy_##dtype##_##dtype(datdest->row[yc], datsrc->row[yc]);	\
									\
  alpha = tan(a);							\
  alpha = (alpha < 0) ? (-1*alpha) : (alpha);				\
									\
  if(angle<0) {								\
    for(i=0,k=yc-1 ; i<yc ; i++,k--) {					\
      shift_circular = (int) (alpha * ((fgFLOAT64) i));			\
      flgr1d_shift_circular_right_##dtype(datdest->row[k],		\
					  datsrc->row[k],		\
					  shift_circular);		\
    }									\
    for(k=yc+1,i=0 ; k<datsrc->size_y ; i++,k++) {			\
      shift_circular = (int) (alpha * ((fgFLOAT64) i));			\
      flgr1d_shift_circular_left_##dtype(datdest->row[k],		\
					 datsrc->row[k],		\
					 shift_circular);		\
    }									\
  }else {								\
    for(i=0,k=yc-1 ; i<yc ; i++,k--) {					\
      shift_circular = (int) (alpha * ((fgFLOAT64) i));			\
      flgr1d_shift_circular_left_##dtype(datdest->row[k],		\
					 datsrc->row[k],		\
					 shift_circular);		\
    }									\
    for(k=yc+1,i=0 ; k<datsrc->size_y ; i++,k++) {			\
      shift_circular = (int) (alpha * ((fgFLOAT64) i));			\
      flgr1d_shift_circular_right_##dtype(datdest->row[k],		\
					  datsrc->row[k],		\
					  shift_circular);		\
    }									\
  }									\
									\
  return


void flgr2d_shear_circular_x_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_X_2D(fgBIT);
}
void flgr2d_shear_circular_x_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_X_2D(fgUINT8);
}
void flgr2d_shear_circular_x_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_X_2D(fgUINT16);
}
void flgr2d_shear_circular_x_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_X_2D(fgUINT32);
}
void flgr2d_shear_circular_x_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_X_2D(fgINT8);
}
void flgr2d_shear_circular_x_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_X_2D(fgINT16);
}
void flgr2d_shear_circular_x_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_X_2D(fgINT32);
}
void flgr2d_shear_circular_x_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_X_2D(fgFLOAT32);
}
void flgr2d_shear_circular_x_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_X_2D(fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Horizontal Shear Circular
 *  @param datdest : pointer to FLGR_Data1D
 *  @param datsrc : pointer to FLGR_Data1D
 *  @param xc : column center
 *  @param yc : row center
 *  @param angle : fgFLOAT64 (degree)
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_shear_circular_x(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(angle>45) {
    POST_ERROR("angle > 45\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if(angle<-45) {
    POST_ERROR("angle < -45\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if((ret = flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__)) != FLGR_RET_OK) return ret;

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr2d_shear_circular_x,datdest,datsrc,xc,yc,angle);

}






#define FLGR_MACRO_SHEAR_CIRCULAR_Y_2D(dtype)				\
  FLGR_Data2D *tdatdest;						\
  FLGR_Data2D *tdatsrc;							\
  fgFLOAT64 alpha,a;							\
  int i,k,shift_circular;						\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  tdatsrc = flgr2d_create_pixmap(datsrc->size_x,datsrc->size_y,		\
				 datsrc->spp,datsrc->type);		\
  tdatdest = flgr2d_create_pixmap(datsrc->size_x,datsrc->size_y,	\
				  datsrc->spp,datsrc->type);		\
									\
  flgr2d_transpose_##dtype(tdatsrc,datsrc);				\
 									\
  a = (angle * FLGR_PI)/180;						\
									\
  flgr1d_copy_##dtype##_##dtype(tdatdest->row[xc], tdatsrc->row[xc]);	\
									\
  alpha = sin(a);							\
  alpha = (alpha < 0) ? (-1*alpha) : (alpha);				\
									\
  if(angle<0) {								\
    for(i=0,k=xc-1 ; i<xc ; i++,k--) {					\
      shift_circular = (int) (alpha * ((fgFLOAT64) i));			\
      flgr1d_shift_circular_left_##dtype(tdatdest->row[k],		\
					 tdatsrc->row[k],		\
					 shift_circular);		\
    }									\
    for(k=xc+1,i=0 ; k<tdatsrc->size_y ; i++,k++) {			\
      shift_circular = (int) (alpha * ((fgFLOAT64) i));			\
      flgr1d_shift_circular_right_##dtype(tdatdest->row[k],		\
					  tdatsrc->row[k],		\
					  shift_circular);		\
    }									\
  }else {								\
    for(i=0,k=xc-1 ; i<xc ; i++,k--) {					\
      shift_circular = (int) (alpha * ((fgFLOAT64) i));			\
      flgr1d_shift_circular_right_##dtype(tdatdest->row[k],		\
					  tdatsrc->row[k],		\
					  shift_circular);		\
    }									\
    for(k=xc+1,i=0 ; k<tdatsrc->size_y ; i++,k++) {			\
      shift_circular = (int) (alpha * ((fgFLOAT64) i));			\
      flgr1d_shift_circular_left_##dtype(tdatdest->row[k],		\
					 tdatsrc->row[k],		\
					 shift_circular);		\
    }									\
  }									\
									\
  flgr2d_transpose_##dtype(datdest,tdatdest);				\
 									\
  flgr2d_destroy(tdatdest);						\
  flgr2d_destroy(tdatsrc)

void flgr2d_shear_circular_y_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_Y_2D(fgBIT);
}
void flgr2d_shear_circular_y_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_Y_2D(fgUINT8);
}
void flgr2d_shear_circular_y_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_Y_2D(fgUINT16);
}
void flgr2d_shear_circular_y_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_Y_2D(fgUINT32);
}
void flgr2d_shear_circular_y_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_Y_2D(fgINT8);
}
void flgr2d_shear_circular_y_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_Y_2D(fgINT16);
}
void flgr2d_shear_circular_y_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_Y_2D(fgINT32);
}
void flgr2d_shear_circular_y_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_Y_2D(fgFLOAT32);
}
void flgr2d_shear_circular_y_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_MACRO_SHEAR_CIRCULAR_Y_2D(fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Horizontal Shear Circular
 *  @param datdest : pointer to FLGR_Data1D
 *  @param datsrc : pointer to FLGR_Data1D
 *  @param xc : column center
 *  @param yc : row center
 *  @param angle : fgFLOAT64 (degree)
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_shear_circular_y(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int xc, int yc, fgFLOAT64 angle) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(angle>90) {
    POST_ERROR("angle > 90\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if(angle<-90) {
    POST_ERROR("angle < -90\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if((ret = flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__)) != FLGR_RET_OK) return ret;

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr2d_shear_circular_y,datdest,datsrc,xc,yc,angle);

}


#define FLGR_MACRO_ROTATE_CENTER(dtype)					\
  int xc = datsrc->size_x/2;						\
  int yc = datsrc->size_y/2;						\
  FLGR_Data2D *dattmp;							\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  dattmp = flgr2d_create_from(datsrc);					\
									\
  if((angle==180) || (angle==-180)) {					\
    flgr2d_mirror_horizontal_##dtype(dattmp,datsrc);			\
    flgr2d_mirror_vertical(datdest,dattmp);				\
									\
  }else if((angle>90) && (angle<180)) {					\
    flgr2d_mirror_horizontal_##dtype(dattmp,datsrc);			\
    flgr2d_mirror_vertical_hmorph(dattmp);				\
    angle = angle-180;							\
    flgr2d_shear_circular_x_##dtype(datdest,dattmp,xc,yc, angle/2);	\
    flgr2d_shear_circular_y_##dtype(dattmp,datdest,xc,yc, angle);	\
    flgr2d_shear_circular_x_##dtype(datdest,dattmp,xc,yc, angle/2);	\
    									\
  }else if((angle < -90) && (angle > -180)) {				\
    flgr2d_mirror_horizontal_##dtype(dattmp,datsrc);			\
    flgr2d_mirror_vertical_hmorph(dattmp);				\
    angle = 180+angle;							\
    flgr2d_shear_circular_x_##dtype(datdest,dattmp,xc,yc, angle/2);	\
    flgr2d_shear_circular_y_##dtype(dattmp,datdest,xc,yc, angle);	\
    flgr2d_shear_circular_x_##dtype(datdest,dattmp,xc,yc, angle/2);	\
    									\
  }else{								\
    flgr2d_shear_circular_x_##dtype(datdest,datsrc,xc,yc, angle/2);	\
    flgr2d_shear_circular_y_##dtype(dattmp,datdest,xc,yc, angle);	\
    flgr2d_shear_circular_x_##dtype(datdest,dattmp,xc,yc, angle/2);	\
    									\
  }									\
    									\
  flgr2d_destroy(dattmp)


void flgr2d_rotate_center_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, fgFLOAT64 angle) {
  FLGR_MACRO_ROTATE_CENTER(fgBIT);
}
void flgr2d_rotate_center_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, fgFLOAT64 angle) {
  FLGR_MACRO_ROTATE_CENTER(fgUINT8);
}
void flgr2d_rotate_center_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, fgFLOAT64 angle) {
  FLGR_MACRO_ROTATE_CENTER(fgUINT16);
}
void flgr2d_rotate_center_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, fgFLOAT64 angle) {
  FLGR_MACRO_ROTATE_CENTER(fgUINT32);
}
void flgr2d_rotate_center_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, fgFLOAT64 angle) {
  FLGR_MACRO_ROTATE_CENTER(fgINT8);
}
void flgr2d_rotate_center_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, fgFLOAT64 angle) {
  FLGR_MACRO_ROTATE_CENTER(fgINT16);
}
void flgr2d_rotate_center_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, fgFLOAT64 angle) {
  FLGR_MACRO_ROTATE_CENTER(fgINT32);
}
void flgr2d_rotate_center_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, fgFLOAT64 angle) {
  FLGR_MACRO_ROTATE_CENTER(fgFLOAT32);
}
void flgr2d_rotate_center_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, fgFLOAT64 angle) {
  FLGR_MACRO_ROTATE_CENTER(fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Rotate image without interpolation
 *  @param datdest : pointer to FLGR_Data1D
 *  @param datsrc : pointer to FLGR_Data1D
 *  @param angle : fgFLOAT64 (degree) ]-180,180]
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_rotate_center(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, fgFLOAT64 angle) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(angle>180) {
    POST_ERROR("angle > 180\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if(angle<-180) {
    POST_ERROR("angle < -180\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if((ret = flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__)) != FLGR_RET_OK) return ret;

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr2d_rotate_center,datdest,datsrc,angle);


}

//! @}
